package tunnel

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	"internal-net-bridge-server/internal/models"
	"internal-net-bridge-server/internal/tunnel/protocols/common"
	// httpProto "internal-net-bridge-server/internal/tunnel/protocols/http" // 已废弃：改用QUIC
)

// ========================================
// 隧道协议处理模块
// ========================================
// 本文件负责处理隧道客户端与服务端之间的协议通信
// 包括协议解析、数据包处理、连接管理

// getHeader 获取HTTP头部（辅助函数，替代已删除的httpProto.GetHeader）
func getHeader(headers map[string][]string, name string) string {
	for key, values := range headers {
		if strings.EqualFold(key, name) && len(values) > 0 {
			return values[0]
		}
	}
	return ""
}

// handleTunnelData 处理来自隧道客户端的数据
// 这是隧道数据处理的主入口
//
// 支持的协议类型：
// 1. HTTP_RESPONSE_START - 分片响应开始
// 2. HTTP_RESPONSE_CHUNK - 分片响应数据
// 3. HTTP_RESPONSE_END - 分片响应结束
// 4. HTTP_RESPONSE_ERROR - 分片响应错误
// 5. HTTP_RESPONSE_PACKET - 旧协议（兼容）
// 6. STREAMING_START - 流式传输开始
// 7. STREAMING_CHUNK - 流式传输数据分片
// 8. STREAMING_END - 流式传输结束
//
// 参数：
//   - tunnel: 隧道信息
//   - reader: 隧道连接的缓冲读取器
//
// 返回：
//   - error: 处理错误
//
// 注意：
//   - 此函数在循环中被调用，负责解析和分发不同类型的协议数据包
//   - 使用bufio.Reader进行缓冲读取，提高性能
func (tm *TunnelManager) handleTunnelData(tunnel *models.Tunnel, reader *bufio.Reader) error {
	// 读取数据包头部
	headerLine, err := reader.ReadString('\n')
	if err != nil {
		if err == io.EOF {
			log.Printf("🔌 隧道连接已关闭 (隧道ID: %s)", tunnel.ID)
			return err
		}
		log.Printf("❌ 读取隧道数据包头部失败:")
		log.Printf("   ├─ 隧道ID: %s", tunnel.ID)
		log.Printf("   └─ 错误: %v", err)
		return err
	}

	headerLine = strings.TrimSpace(headerLine)

	// 🐛 调试：打印所有收到的数据包头部（临时调试）
	if len(headerLine) > 0 {
		sample := headerLine
		if len(sample) > 100 {
			sample = sample[:100] + "..."
		}
		log.Printf("📥 [调试] 收到数据包: %s", sample)
	}

	// ⚠️ 旧的TCP隧道协议已废弃，现在使用QUIC
	// 以下协议消息不再处理
	if strings.HasPrefix(headerLine, "HTTP_RESPONSE_START:") ||
		strings.HasPrefix(headerLine, "HTTP_RESPONSE_CHUNK:") ||
		strings.HasPrefix(headerLine, "HTTP_RESPONSE_END:") ||
		strings.HasPrefix(headerLine, "HTTP_RESPONSE_ERROR:") {
		log.Printf("⚠️ [DEPRECATED] 收到旧协议消息，已废弃: %s", headerLine)
		return fmt.Errorf("旧的TCP隧道协议已废弃，请使用QUIC")
	}

	// 处理旧协议：HTTP_RESPONSE_PACKET（兼容旧版本）
	if strings.HasPrefix(headerLine, "HTTP_RESPONSE_PACKET:") {
		// 解析旧协议：HTTP_RESPONSE_PACKET:requestID:dataLength
		parts := strings.Split(headerLine, ":")
		if len(parts) != 3 {
			return fmt.Errorf("无效的HTTP_RESPONSE_PACKET格式: %s", headerLine)
		}

		requestID := parts[1]
		dataLength, err := strconv.Atoi(parts[2])
		if err != nil {
			return fmt.Errorf("无效的数据长度: %s", parts[2])
		}

		// 🔥 性能优化：减少日志输出（只在前10个或大于1MB时打印）
		if tm.unknownPacketCount < 10 || dataLength > 1024*1024 {
			log.Printf("📦 收到响应数据包 (请求ID: %s, 数据长度: %d bytes)", requestID, dataLength)
		}

		// 获取对应的连接
		tm.connMapMutex.RLock()
		streamingConn, connExists := tm.connectionMap[requestID]
		tm.connMapMutex.RUnlock()

		if !connExists || streamingConn == nil {
			// 消耗数据避免协议错位（静默处理，减少日志噪音）
			io.CopyN(io.Discard, reader, int64(dataLength))
			return nil
		}

		// 🔥🔥🔥 性能优化：使用缓冲池避免频繁内存分配
		responseData := common.GetBuffer(dataLength)
		defer common.PutBuffer(responseData) // 归还缓冲区

		if _, err := io.ReadFull(reader, responseData); err != nil {
			log.Printf("❌ 读取响应数据失败: %v", err)
			return err
		}

		// 直接转发响应数据到客户端（减少超时设置开销）
		if _, err := streamingConn.Conn.Write(responseData); err != nil {
			// 静默处理写入失败（连接可能已关闭）
			return nil
		}

		// 清理映射
		tm.connMapMutex.Lock()
		delete(tm.connectionMap, requestID)
		tm.connMapMutex.Unlock()

		tunnel.MapMutex.Lock()
		delete(tunnel.RequestMap, requestID)
		tunnel.MapMutex.Unlock()

		return nil
	}

	// 处理流式传输协议
	if strings.HasPrefix(headerLine, "STREAMING_START:") {
		return tm.handleStreamingStart(tunnel, reader, headerLine)
	}

	if strings.HasPrefix(headerLine, "STREAMING_CHUNK:") {
		return tm.handleStreamingChunk(tunnel, reader, headerLine)
	}

	if strings.HasPrefix(headerLine, "STREAMING_END:") {
		return tm.handleStreamingEnd(tunnel, headerLine)
	}

	// 🔥🔥🔥 严格过滤二进制数据（连接关闭残留、TLS握手、损坏协议）
	// 检测策略：
	// 1. 空行：直接跳过
	// 2. 纯二进制（>30%非打印字符）：静默跳过
	// 3. 只在前3次打印样本（避免日志泛滥）

	// 空行直接跳过
	if len(headerLine) == 0 {
		return nil
	}

	// 检测二进制数据
	nonPrintableCount := 0
	printableCount := 0
	for _, r := range headerLine {
		if r < 32 && r != '\n' && r != '\r' && r != '\t' {
			nonPrintableCount++
		} else if r >= 32 && r < 127 {
			printableCount++
		}
	}

	// 🔥 降低阈值到30%，更严格地过滤二进制数据
	// 原因：正常文本协议的非打印字符应该<10%
	if len(headerLine) > 0 && float64(nonPrintableCount)/float64(len(headerLine)) > 0.3 {
		// 静默跳过二进制残留数据（完全不打印日志）
		tm.unknownPacketMutex.Lock()
		tm.unknownPacketCount++
		tm.unknownPacketMutex.Unlock()
		return nil
	}

	// 🔥 极简日志：只打印前3次样本
	tm.unknownPacketMutex.Lock()
	tm.unknownPacketCount++
	count := tm.unknownPacketCount
	tm.unknownPacketMutex.Unlock()

	if count <= 3 {
		// 只打印前3次，用于初步调试
		sample := headerLine
		if len(sample) > 50 {
			sample = sample[:50] + "..."
		}
		log.Printf("⚠️ [调试] 未知数据包 #%d: %s", count, sample)
	}

	// 返回nil，容忍偶发的协议错误（不断开连接）
	return nil
}

// handleStreamingStart 处理流式传输开始数据包
//
// 协议格式：STREAMING_START:requestID:statusCode:headerLength\r\n[headers]
//
// 功能：
// 1. 解析请求ID、状态码、响应头长度
// 2. 读取HTTP响应头
// 3. 查找对应的客户端连接（支持Range请求）
// 4. 发送HTTP响应头到客户端
//
// 参数：
//   - tunnel: 隧道信息
//   - reader: 隧道连接的缓冲读取器
//   - headerLine: 协议头部行
//
// 返回：
//   - error: 处理错误
func (tm *TunnelManager) handleStreamingStart(tunnel *models.Tunnel, reader *bufio.Reader, headerLine string) error {
	// 解析：STREAMING_START:requestID:statusCode:headerLength
	parts := strings.Split(headerLine, ":")
	if len(parts) != 4 {
		return fmt.Errorf("无效的STREAMING_START格式: %s", headerLine)
	}

	requestID := parts[1]
	statusCode, err := strconv.Atoi(parts[2])
	if err != nil {
		return fmt.Errorf("无效的状态码: %s", parts[2])
	}
	headerLength, err := strconv.Atoi(parts[3])
	if err != nil {
		return fmt.Errorf("无效的头部长度: %s", parts[3])
	}

	log.Printf("🎬 [流式传输] 开始: 请求ID=%s, 状态码=%d, 头部长度=%d", requestID, statusCode, headerLength)

	// 读取响应头部
	headerData := make([]byte, headerLength)
	if _, err := io.ReadFull(reader, headerData); err != nil {
		return fmt.Errorf("读取流式传输头部失败: %v", err)
	}

	// 解析响应头
	response := &models.HTTPResponse{
		StatusCode: statusCode,
		Headers:    make(map[string][]string),
		Body:       nil,
	}

	headerLines := strings.Split(string(headerData), "\r\n")
	for _, line := range headerLines {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		colonIndex := strings.Index(line, ":")
		if colonIndex == -1 {
			continue
		}
		headerName := strings.TrimSpace(line[:colonIndex])
		headerValue := strings.TrimSpace(line[colonIndex+1:])
		response.Headers[headerName] = append(response.Headers[headerName], headerValue)
	}

	// 获取连接
	tm.connMapMutex.RLock()
	streamingConn, connExists := tm.connectionMap[requestID]

	// 如果请求ID找不到，尝试从隧道的请求映射中获取连接地址（Range请求）
	if !connExists {
		tunnel.MapMutex.RLock()
		if httpReq, reqExists := tunnel.RequestMap[requestID]; reqExists {
			// 检查是否为Range请求
			if rangeHeader := getHeader(httpReq.Headers, "Range"); rangeHeader != "" {
				// 尝试使用连接地址查找
				for connKey, conn := range tm.connectionMap {
					if conn.Conn != nil && conn.Conn.RemoteAddr() != nil {
						// 找到对应的连接
						streamingConn = conn
						connExists = true
						log.Printf("🎯 Range请求响应通过连接地址找到连接: %s (请求ID: %s)", connKey, requestID)
						break
					}
				}
			}
		}
		tunnel.MapMutex.RUnlock()
	}
	tm.connMapMutex.RUnlock()

	if !connExists || streamingConn == nil {
		log.Printf("❌ 连接不存在或已关闭，无法发送流式传输头部 (请求ID: %s)", requestID)
		return nil
	}

	// 确保添加下载工具需要的关键头部
	tm.ensureDownloadHeaders(response.Headers, response.StatusCode)

	// 更新最后使用时间
	tm.connMapMutex.Lock()
	streamingConn.LastUsed = time.Now()
	tm.connMapMutex.Unlock()

	// 发送响应头部（构建HTTP响应字节）
	var responseBytes []byte
	responseBytes = append(responseBytes, []byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", response.StatusCode, http.StatusText(response.StatusCode)))...)
	for key, value := range response.Headers {
		responseBytes = append(responseBytes, []byte(fmt.Sprintf("%s: %s\r\n", key, value))...)
	}
	responseBytes = append(responseBytes, []byte("\r\n")...)

	_, err = streamingConn.Conn.Write(responseBytes)
	if err != nil {
		log.Printf("❌ 发送响应头部失败 (请求ID: %s): %v", requestID, err)
		return err
	}
	log.Printf("✅ 流式传输头部已发送 (请求ID: %s)", requestID)

	return nil
}

// handleStreamingChunk 处理流式传输数据分片
//
// 协议格式：STREAMING_CHUNK:requestID:chunkSize\r\n[chunkData]
//
// 功能：
// 1. 解析请求ID和分片大小
// 2. 读取分片数据
// 3. 查找对应的客户端连接（支持Range请求）
// 4. 检测连接健康状态
// 5. 发送分片数据到客户端（大分片会分块发送）
//
// 参数：
//   - tunnel: 隧道信息
//   - reader: 隧道连接的缓冲读取器
//   - headerLine: 协议头部行
//
// 返回：
//   - error: 处理错误
func (tm *TunnelManager) handleStreamingChunk(tunnel *models.Tunnel, reader *bufio.Reader, headerLine string) error {
	// 解析：STREAMING_CHUNK:requestID:chunkSize
	parts := strings.Split(headerLine, ":")
	if len(parts) != 3 {
		return fmt.Errorf("无效的STREAMING_CHUNK格式: %s", headerLine)
	}

	requestID := parts[1]
	chunkSize, err := strconv.Atoi(parts[2])
	if err != nil {
		return fmt.Errorf("无效的分片大小: %s", parts[2])
	}

	// 🔥 性能优化：先查找连接，避免无效分配
	tm.connMapMutex.RLock()
	streamingConn, connExists := tm.connectionMap[requestID]

	// 如果请求ID找不到，尝试从隧道的请求映射中获取连接地址
	if !connExists {
		tunnel.MapMutex.RLock()
		if httpReq, reqExists := tunnel.RequestMap[requestID]; reqExists {
			// 检查是否为Range请求
			if rangeHeader := getHeader(httpReq.Headers, "Range"); rangeHeader != "" {
				// 尝试使用连接地址查找
				for _, conn := range tm.connectionMap {
					if conn.Conn != nil && conn.Conn.RemoteAddr() != nil {
						// 找到对应的连接
						streamingConn = conn
						connExists = true
						break
					}
				}
			}
		}
		tunnel.MapMutex.RUnlock()
	}
	tm.connMapMutex.RUnlock()

	if !connExists || streamingConn == nil {
		// 连接不存在，静默丢弃数据
		io.CopyN(io.Discard, reader, int64(chunkSize))
		return nil
	}

	// 🔥🔥🔥 性能优化：使用缓冲池避免频繁内存分配
	chunkData := common.GetBuffer(chunkSize)
	defer common.PutBuffer(chunkData) // 归还缓冲区

	if _, err := io.ReadFull(reader, chunkData); err != nil {
		return fmt.Errorf("读取流式传输分片失败: %v", err)
	}

	conn := streamingConn.Conn

	// 更新最后使用时间
	tm.connMapMutex.Lock()
	streamingConn.LastUsed = time.Now()
	tm.connMapMutex.Unlock()

	// 改进的连接健康检查：使用TCP连接状态检查
	if tcpConn, ok := conn.(*net.TCPConn); ok {
		// 设置短暂的读取超时来检测连接状态
		tcpConn.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
		buffer := make([]byte, 1)
		_, err := tcpConn.Read(buffer)

		// 重置读取超时
		tcpConn.SetReadDeadline(time.Time{})

		// 如果连接已断开，会返回特定错误
		if err != nil {
			if netErr, ok := err.(net.Error); ok && !netErr.Timeout() {
				// 非超时错误表示连接可能已断开
				if common.IsConnectionError(err) {
					log.Printf("🔌 连接健康检查失败，连接已断开 (请求ID: %s): %v", requestID, err)
					tm.connMapMutex.Lock()
					delete(tm.connectionMap, requestID)
					tm.connMapMutex.Unlock()
					return nil
				}
			}
		}
	}

	// 直接发送分片数据到客户端
	if len(chunkData) > 0 {
		// 对于大分片，使用分块发送避免网络超时
		if len(chunkData) > 1024*1024 { // 1MB以上使用分块发送
			log.Printf("📦 大分片分块发送: %d bytes (请求ID: %s)", len(chunkData), requestID)
			totalSent := tm.sendLargeChunkInParts(conn, chunkData, requestID, tunnel)
			if totalSent != len(chunkData) {
				log.Printf("⚠️ 大分片发送不完整: 期望 %d bytes, 实际 %d bytes", len(chunkData), totalSent)
				// 发送失败时，清理连接映射和请求映射
				tm.connMapMutex.Lock()
				delete(tm.connectionMap, requestID)
				tm.connMapMutex.Unlock()

				tunnel.MapMutex.Lock()
				delete(tunnel.RequestMap, requestID)
				remainingRequests := len(tunnel.RequestMap)
				tunnel.MapMutex.Unlock()

				log.Printf("🧹 大分片发送失败，清理请求映射 (请求ID: %s), 剩余请求: %d", requestID, remainingRequests)
				return nil
			}
		} else {
			// 小分片直接发送
			conn.SetWriteDeadline(time.Now().Add(30 * time.Second))
			n, err := conn.Write(chunkData)
			if err != nil {
				if common.IsConnectionError(err) {
					log.Printf("🔌 客户端断开连接，停止发送分片: %v (请求ID: %s)", err, requestID)
				} else {
					log.Printf("❌ 发送流式传输分片失败:")
					log.Printf("   ├─ 请求ID: %s", requestID)
					log.Printf("   ├─ 分片大小: %d bytes", len(chunkData))
					log.Printf("   └─ 错误: %v", err)
				}
				// 发送失败时，清理连接映射和请求映射
				tm.connMapMutex.Lock()
				delete(tm.connectionMap, requestID)
				tm.connMapMutex.Unlock()

				// 同时清理隧道请求映射，避免后续分片继续处理
				tunnel.MapMutex.Lock()
				delete(tunnel.RequestMap, requestID)
				remainingRequests := len(tunnel.RequestMap)
				tunnel.MapMutex.Unlock()

				log.Printf("🧹 连接断开，清理请求映射 (请求ID: %s), 剩余请求: %d", requestID, remainingRequests)
				return nil
			} else {
				// 只在重要节点输出日志，避免过多输出
				if len(chunkData) > 64*1024 {
					log.Printf("📦 流式传输分片已发送: %d bytes (请求ID: %s)", n, requestID)
				}
				if n != len(chunkData) {
					log.Printf("⚠️ 分片发送不完整: 期望 %d bytes, 实际 %d bytes (请求ID: %s)",
						len(chunkData), n, requestID)
				}
			}
		}
	}

	return nil
}

// handleStreamingEnd 处理流式传输结束
//
// 协议格式：STREAMING_END:requestID\r\n
//
// 功能：
// 1. 解析请求ID
// 2. 判断是否为Range请求
// 3. Range请求：保持连接以便复用
// 4. 非Range请求：关闭连接
// 5. 清理请求映射
//
// 参数：
//   - tunnel: 隧道信息
//   - headerLine: 协议头部行
//
// 返回：
//   - error: 处理错误
//
// 注意：
//   - Range请求的连接不会立即关闭，而是保留给后续Range请求使用
//   - 连接清理器会定期清理过期的连接
func (tm *TunnelManager) handleStreamingEnd(tunnel *models.Tunnel, headerLine string) error {
	// 解析：STREAMING_END:requestID
	parts := strings.Split(headerLine, ":")
	if len(parts) != 2 {
		return fmt.Errorf("无效的STREAMING_END格式: %s", headerLine)
	}

	requestID := parts[1]

	log.Printf("✅ 流式传输结束:")
	log.Printf("   ├─ 隧道ID: %s", tunnel.ID)
	log.Printf("   └─ 请求ID: %s", requestID)

	// 检查是否为Range请求
	tunnel.MapMutex.RLock()
	httpReq, reqExists := tunnel.RequestMap[requestID]
	isRangeRequest := reqExists && getHeader(httpReq.Headers, "Range") != ""
	tunnel.MapMutex.RUnlock()

	// 获取连接
	tm.connMapMutex.Lock()
	var streamingConn *StreamingConnection
	var connExists bool

	if isRangeRequest {
		// Range请求不立即关闭连接，让连接清理器处理
		streamingConn, connExists = tm.connectionMap[requestID]
		if connExists && streamingConn != nil {
			// 只更新最后使用时间，不关闭连接
			streamingConn.LastUsed = time.Now()
			log.Printf("🔄 Range请求保持连接以便复用 (请求ID: %s)", requestID)
		}
	} else {
		// 非Range请求，立即关闭连接
		streamingConn, connExists = tm.connectionMap[requestID]
		if connExists && streamingConn != nil && streamingConn.Conn != nil {
			streamingConn.Conn.Close()
			log.Printf("🔌 已关闭客户端连接 (请求ID: %s)", requestID)
		}
		delete(tm.connectionMap, requestID)
	}
	tm.connMapMutex.Unlock()

	// 清理请求映射
	tunnel.MapMutex.Lock()
	delete(tunnel.RequestMap, requestID)
	remainingRequests := len(tunnel.RequestMap)
	tunnel.MapMutex.Unlock()

	log.Printf("🧹 请求映射已清理 (请求ID: %s), 剩余请求: %d", requestID, remainingRequests)

	return nil
}

// ========================================
// sendHTTPResponse 方法已在 http_parser.go 中定义
// ========================================

// ensureDownloadHeaders 确保响应头包含下载工具需要的关键头部
//
// 功能：
// 为下载工具（如迅雷、IDM）添加必要的HTTP响应头
//
// 添加的头部：
// 1. Accept-Ranges: bytes（支持范围请求）
// 2. Connection: keep-alive（保持连接）
// 3. 对206响应，确保有Content-Range头
//
// 参数：
//   - headers: 响应头映射
//   - statusCode: HTTP状态码
func (tm *TunnelManager) ensureDownloadHeaders(headers map[string][]string, statusCode int) {
	// 确保有Accept-Ranges头
	if _, exists := headers["Accept-Ranges"]; !exists {
		headers["Accept-Ranges"] = []string{"bytes"}
	}

	// 确保有Connection头
	if _, exists := headers["Connection"]; !exists {
		headers["Connection"] = []string{"keep-alive"}
	}

	// 对于206响应，确保有Content-Range头
	if statusCode == 206 {
		if _, exists := headers["Content-Range"]; !exists {
			log.Printf("⚠️ 206响应缺少Content-Range头")
		}
	}
}

// ========================================
// isConnectionError 函数已移至 http_parser.go
// ========================================

// ❌ getStatusText已删除（未使用）

// ========================================
// getHeader 函数已移至 http_parser.go
// ========================================

// sendLargeChunkInParts 分块发送大数据，避免网络超时
//
// 参数：
//   - conn: 目标连接
//   - data: 要发送的数据
//   - requestID: 请求ID（用于日志）
//   - tunnel: 隧道信息（用于错误处理）
//
// 返回：
//   - int: 实际发送的字节数
func (tm *TunnelManager) sendLargeChunkInParts(conn net.Conn, data []byte, requestID string, tunnel *models.Tunnel) int {
	const chunkSize = 64 * 1024 // 64KB 分块大小
	totalSent := 0
	dataLen := len(data)

	log.Printf("📦 开始分块发送大数据: 总大小 %d bytes (%.2f MB), 分块大小: %d KB, 请求ID: %s",
		dataLen, float64(dataLen)/(1024*1024), chunkSize/1024, requestID)

	for offset := 0; offset < dataLen; offset += chunkSize {
		end := offset + chunkSize
		if end > dataLen {
			end = dataLen
		}

		chunk := data[offset:end]
		chunkLen := len(chunk)

		// 设置每个分块的写入超时
		conn.SetWriteDeadline(time.Now().Add(10 * time.Second))

		n, err := conn.Write(chunk)
		totalSent += n

		if err != nil {
			log.Printf("❌ 发送分块失败: %v (已发送: %d/%d bytes, 请求ID: %s)",
				err, totalSent, dataLen, requestID)
			return totalSent
		}

		if n != chunkLen {
			log.Printf("⚠️ 分块发送不完整: 期望 %d bytes, 实际 %d bytes (请求ID: %s)",
				chunkLen, n, requestID)
		}

		// 每发送1MB输出一次进度
		if totalSent%(1024*1024) < chunkLen || totalSent == dataLen {
			progress := float64(totalSent) / float64(dataLen) * 100
			log.Printf("📈 发送进度: %d/%d bytes (%.1f%%), 请求ID: %s",
				totalSent, dataLen, progress, requestID)
		}
	}

	log.Printf("✅ 分块发送完成: %d bytes, 请求ID: %s", totalSent, requestID)
	return totalSent
}
